﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Algorithm;

namespace YJKGridTopologyCal.Noding
{
	public class InteriorIntersectionFinder : ISegmentIntersector
	{
		public static InteriorIntersectionFinder CreateAnyIntersectionFinder(LineIntersector li)
		{
			return new InteriorIntersectionFinder(li);
		}

		public static InteriorIntersectionFinder CreateAllIntersectionsFinder(LineIntersector li)
		{
			return new InteriorIntersectionFinder(li)
			{
				FindAllIntersections = true
			};
		}

		public static InteriorIntersectionFinder CreateIntersectionCounter(LineIntersector li)
		{
			return new InteriorIntersectionFinder(li)
			{
				FindAllIntersections = true,
				KeepIntersections = false
			};
		}

		public InteriorIntersectionFinder(LineIntersector li)
		{
			this._li = li;
			this._interiorIntersection = null;
		}

		public bool FindAllIntersections { get; set; }

		public bool KeepIntersections
		{
			get
			{
				return this._keepIntersections;
			}
			set
			{
				this._keepIntersections = value;
			}
		}

		public bool CheckEndSegmentsOnly { get; set; }

		public bool HasIntersection
		{
			get
			{
				return this._interiorIntersection != null;
			}
		}

		public IList<Coordinate> Intersections
		{
			get
			{
				return new ReadOnlyCollection<Coordinate>(this._intersections);
			}
		}

		public int Count
		{
			get
			{
				return this.intersectionCount;
			}
		}

		public Coordinate InteriorIntersection
		{
			get
			{
				return this._interiorIntersection;
			}
		}

		public Coordinate[] IntersectionSegments
		{
			get
			{
				return this._intSegments;
			}
		}

		public void ProcessIntersections(ISegmentString e0, int segIndex0, ISegmentString e1, int segIndex1)
		{
			if (!this.FindAllIntersections && this.HasIntersection)
			{
				return;
			}
			if (e0 == e1 && segIndex0 == segIndex1)
			{
				return;
			}
			if (this.CheckEndSegmentsOnly && !InteriorIntersectionFinder.IsEndSegment(e0, segIndex0) && !InteriorIntersectionFinder.IsEndSegment(e1, segIndex1))
			{
				return;
			}
			Coordinate coordinate = e0.Coordinates[segIndex0];
			Coordinate coordinate2 = e0.Coordinates[segIndex0 + 1];
			Coordinate coordinate3 = e1.Coordinates[segIndex1];
			Coordinate coordinate4 = e1.Coordinates[segIndex1 + 1];
			this._li.ComputeIntersection(coordinate, coordinate2, coordinate3, coordinate4);
			if (this._li.HasIntersection && this._li.IsInteriorIntersection())
			{
				this._intSegments = new Coordinate[4];
				this._intSegments[0] = coordinate;
				this._intSegments[1] = coordinate2;
				this._intSegments[2] = coordinate3;
				this._intSegments[3] = coordinate4;
				this._interiorIntersection = this._li.GetIntersection(0);
				if (this.KeepIntersections)
				{
					this._intersections.Add(this._interiorIntersection);
				}
				this.intersectionCount++;
			}
		}

		private static bool IsEndSegment(ISegmentString segStr, int index)
		{
			return index == 0 || index >= segStr.Count - 2;
		}

		public bool IsDone
		{
			get
			{
				return !this.FindAllIntersections && this._interiorIntersection != null;
			}
		}

		private readonly LineIntersector _li;

		private Coordinate _interiorIntersection;

		private Coordinate[] _intSegments;

		private readonly List<Coordinate> _intersections = new List<Coordinate>();

		private int intersectionCount;

		private bool _keepIntersections = true;
	}
}
